/* Emacs style mode select   -*- C++ -*- */
/*-----------------------------------------------------------------------------*/

/* $Id:$*/

/* Copyright (C) 1993-1996 by id Software, Inc.*/

/* This source is available for distribution and/or modification*/
/* only under the terms of the DOOM Source Code License as*/
/* published by id Software. All rights reserved.*/

/* The source is distributed in the hope that it will be useful,*/
/* but WITHOUT ANY WARRANTY; without even the implied warranty of*/
/* FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License*/
/* for more details.*/

/* $Log:$*/

/* DESCRIPTION:*/
/*	Mission begin melt/wipe screen special effect.*/

/*-----------------------------------------------------------------------------*/


static const char rcsid[] = "$Id: f_wipe.c,v 1.2 1997/02/03 22:45:09 b1 Exp $";



#include "z_zone.h"
#include "i_video.h"
#include "i_system.h"
#include "v_video.h"
#include "m_random.h"

#include "doomdef.h"

#include "f_wipe.h"


/*                       SCREEN WIPE PACKAGE*/


/* when zero, stop the wipe*/
static boolean	go = 0;

static pixel_t*	wipe_scr_start;
static pixel_t*	wipe_scr_end;
static pixel_t*	wipe_scr;

/* This system is very tedious in different colour depths... */
#if 0
static void
wipe_shittyColMajorXform
( short*	array,
  int		width,
  int		height )
{
    int		x;
    int		y;
    short*	dest;

    dest = (short*) Z_Malloc(width*height*2, PU_STATIC, 0);

    for(y=0;y<height;y++)
	for(x=0;x<width;x++)
	    dest[x*height+y] = array[y*width+x];

    memcpy(array, dest, width*height*2);

    Z_Free(dest);

}
#endif


static int
wipe_initColorXForm
( int	width,
  int	height,
  int	ticks )
{
    memcpy(wipe_scr, wipe_scr_start, width*height*sizeof(pixel_t));
    return 0;
}

static int
wipe_doColorXForm
( int	width,
  int	height,
  int	ticks )
{
    boolean	changed;
    pixel_t*	w;
    pixel_t*	e;
    int		newval;

    changed = false;
    w = wipe_scr;
    e = wipe_scr_end;

    while (w!=wipe_scr+width*height)
    {
	if (*w != *e)
	{
	    if (*w > *e)
	    {
		newval = *w - ticks;
		if (newval < *e)
		    *w = *e;
		else
		    *w = newval;
		changed = true;
	    }
	    else if (*w < *e)
	    {
		newval = *w + ticks;
		if (newval > *e)
		    *w = *e;
		else
		    *w = newval;
		changed = true;
	    }
	}
	w++;
	e++;
    }

    return !changed;

}

static int
wipe_exitColorXForm
( int	width,
  int	height,
  int	ticks )
{
    return 0;
}


static int*	y = NULL;

static int
wipe_initMelt
( int	width,
  int	height,
  int	ticks )
{
    int i, r;

    /* copy start screen to main screen*/
    memcpy(wipe_scr, wipe_scr_start, width*height*sizeof(pixel_t));

#if 0
    /* makes this wipe faster (in theory)*/
    /* to have stuff in column-major format*/
    wipe_shittyColMajorXform((short*)wipe_scr_start, width/2, height);
    wipe_shittyColMajorXform((short*)wipe_scr_end, width/2, height);
#endif

    /* setup initial column positions*/
    /* (y<0 => not ready to scroll yet)*/
    y = (int *) Z_Malloc(width*sizeof(int), PU_STATIC, 0);
    if (y == NULL)
    {
	I_Error("f_wipe: unable to claim memory!");
    }
    y[0] = -(M_Random()%16); y[1] = y[0];
    for (i=2;i<width;i+=2)
    {
	r = (M_Random()%3) - 1;
	y[i] = y[i-2] + r;
	if (y[i] > 0) y[i] = 0;
	else if (y[i] == -16) y[i] = -15;
	y[i+1] = y[i];
    }
#ifdef __riscos__
    /* for some reason the displayed screen might have changed on occasion */
    I_DisplayFrameBuffer(wipe_scr);
#endif

    return 0;
}

/*
 *  Changed: copies each column rather than always merging two. Also doesn't
 *  expect screens in column-major format anymore.
 */
static int
wipe_doMelt
( int	width,
  int	height,
  int	ticks )
{
    int		i;
    int		j;
    int		dy;
    int		idx;

    pixel_t*	s;
    pixel_t*	d;
    boolean	done = true;

    while (ticks--)
    {
	for (i=0;i<width;i++)
	{
	    if (y[i]<0)
	    {
		y[i]++; done = false;
	    }
	    else if (y[i] < height)
	    {
		dy = (y[i] < 16) ? y[i]+1 : 8;
		if (y[i]+dy >= height) dy = height - y[i];
		s = wipe_scr_end + y[i]*width + i;
		d = wipe_scr + y[i]*width + i;
		idx = 0;
		for (j=dy;j;j--)
		{
		    d[idx] = s[idx];
		    idx += width;
		}
		y[i] += dy;
		s = wipe_scr_start + i;
		d = wipe_scr + y[i]*width + i;
		idx = 0;
		for (j=height-y[i];j;j--)
		{
		    d[idx] = s[idx];
		    idx += width;
		}
		done = false;
	    }
	}
    }

    return done;

}

static int
wipe_exitMelt
( int	width,
  int	height,
  int	ticks )
{
    Z_Free(y);
    return 0;
}

int
wipe_StartScreen
( int	x,
  int	y,
  int	width,
  int	height )
{
#ifdef __riscos__
    wipe_scr_start = I_GetDisplayedScreen();
#else
    wipe_scr_start = screens[2];
    I_ReadScreen(wipe_scr_start);
#endif
    return 0;
}

int
wipe_EndScreen
( int	x,
  int	y,
  int	width,
  int	height )
{
#ifdef __riscos__
    wipe_scr_end = I_GetSpareScreen();
#else
    wipe_scr_end = screens[3];
#endif
    I_ReadScreen(wipe_scr_end);
    V_DrawBlock(x, y, 0, width, height, wipe_scr_start); /* restore start scr.*/
    return 0;
}

int
wipe_ScreenWipe
( int	wipeno,
  int	x,
  int	y,
  int	width,
  int	height,
  int	ticks )
{
    int rc;
    static int (*wipes[])(int, int, int) =
    {
	wipe_initColorXForm, wipe_doColorXForm, wipe_exitColorXForm,
	wipe_initMelt, wipe_doMelt, wipe_exitMelt
    };

    /* initial stuff*/
    if (!go)
    {
	go = 1;
	/* wipe_scr = (byte *) Z_Malloc(width*height, PU_STATIC, 0); // DEBUG*/
	wipe_scr = screens[0];
	(*wipes[wipeno*3])(width, height, ticks);
    }

    /* do a piece of wipe-in*/
    V_MarkRect(0, 0, width, height);
    rc = (*wipes[wipeno*3+1])(width, height, ticks);
    /*  V_DrawBlock(x, y, 0, width, height, wipe_scr); // DEBUG*/

    /* final stuff*/
    if (rc)
    {
	go = 0;
	(*wipes[wipeno*3+2])(width, height, ticks);
    }

    return !go;

}
